﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Threading;

namespace PWAsker
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public const String PW_REGEX = "%PW%";
        public const String CONFIGFILE = "settings.xml";

        //Is set to true if commands are running. 
        //Used for Window-exit-button to prvent application-closing during execution
        private Boolean commandsActive = false;
        private Double dProgressbarMaximum;

        private Configuration config;

        public MainWindow()
        {
            InitializeComponent();
            passwordField.Focus();
        }

        private void buttonOK_Click(object sender, RoutedEventArgs eventArgs)
        {

            if (config == null)
            {
                Debug.WriteLine("Config file not loaded. Attemting to load it now");
                config = Configuration.readConfiguration(CONFIGFILE);
            }

            //Executing commands, if config was load
            if (config != null)
            {
                Thread execThread = new Thread(new ParameterizedThreadStart(executeCurrentExecutables));
                execThread.Start(passwordField.Password);
                passwordField.Clear();
            }
        }

        //setting ProgrssBars maximum
        public void setProgresbarMaximum(Double dProgbarMax)
        {
            dProgressbarMaximum = dProgbarMax;
            dispatchedExecute(delegate() { progressBar.Maximum = dProgbarMax; });
        }

        //used to update ProgressBar
        public void setProgresbarValue(Double dProgbarVal)
        {
            while (dProgbarVal >= dProgressbarMaximum)
            {
                dProgbarVal -= dProgressbarMaximum;
            }

            dispatchedExecute(delegate() { progressBar.Value = dProgbarVal; });
        }

        //executes actions via the this-dispatcher
        private void dispatchedExecute(System.Action sysAction)
        {
            this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Action(sysAction));
        }

        private void executeCurrentExecutables(Object objPassword)
        {
            String szPassword = objPassword as String;
            Boolean allExecsSucessfull = true;
            List<Executable> lSzExecutable = config.getCurrentExecutables();
            
            for (int i = 0; i < lSzExecutable.Count; i++)
            {
                //Setting the stage: progressBar
                dispatchedExecute(delegate() { ProgresbarLabel.Content = "Step " + (i + 1) + " of " + (lSzExecutable.Count); });

                //Executing executables
                DisableContols(lSzExecutable.ElementAt(i).getBinaryname());
                lSzExecutable.ElementAt(i).execute(szPassword, PW_REGEX, this);
                EnableContols();

                if (lSzExecutable.ElementAt(i).wasSucessfull())
                {
                    Debug.WriteLine("Executable " + lSzExecutable.ElementAt(i).ExecCommand + " had completed sucessfully");
                }
                else
                {
                    Debug.WriteLine("Executable " + lSzExecutable.ElementAt(i).ExecCommand + " had NOT completed sucessfully");
                    allExecsSucessfull = false;
                }
            }

            //closing application if allExecsSucessfull (all executables executed sucessfully) and 
            //EndOnSucessfullExecute (End if all executables executed sucessfully) are both true
            if (allExecsSucessfull)
            {
                Debug.WriteLine("All executables had been executed sucessfully");
                if (config.EndOnSucessfullExecute)
                {
                    Debug.WriteLine("EndOnSucessfullExecute is true. Exiting...");
                    
                    this.Dispatcher.Invoke
                    (
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new System.Action
                        (
                            delegate()
                            {
                                Close();
                            }
                        )
                    );  
                }
            }
        }

        private void buttonConfig_Click(object sender, RoutedEventArgs eventArgs)
        {
            
            if (config == null)
            {
                Debug.WriteLine("Config file not loaded. Attemting to load it now");
                config = Configuration.readConfiguration(CONFIGFILE);
            }


            //Starting configuration-dialog, only if executables is not empty e.g. the setting file was read
            if (config != null)
            {
                List<Executable> lSzCommands = new List<Executable>(config.getCurrentExecutables());

                Debug.WriteLine("Starting configuration window");

                Debug.WriteLine("executables before config");
                debugDumpList(lSzCommands);
                Debug.WriteLine("EndOnSucessfullExecute = " + config.EndOnSucessfullExecute);

                ConfigurationWnd confWnd = new ConfigurationWnd(lSzCommands, config);
                confWnd.Owner = this;
                confWnd.ShowDialog();

                Debug.WriteLine("executables after config");
                debugDumpList(lSzCommands);
                Debug.WriteLine("EndOnSucessfullExecute = " + config.EndOnSucessfullExecute);

                if (confWnd.madeChanges())
                {
                    Debug.WriteLine("configuration changed. Rewriting xml-file");
                    
                    //deleting old executables
                    config.clearExecutables();

                    //adding new executables
                    for (int i = 0; i < lSzCommands.Count; i++)
                    {
                        config.addExecutable(new Executable(lSzCommands.ElementAt(i).ExecCommand, lSzCommands.ElementAt(i).WaitForCommand, lSzCommands.ElementAt(i).WaitSecs));
                    }

                    Debug.WriteLine("The configuration contains the following Executables (full dump):");
                    debugDumpList(config.getCurrentExecutables());

                    Configuration.writeConfiguration(config,CONFIGFILE);
                }
                else
                {
                    Debug.WriteLine("No changes in cofiguration detected. No need for rewriting xml-file");
                }
            }

            
        }

        private void debugDumpList(List<Executable> ExecList)
        {
            for (int i = 0; i < ExecList.Count; i++)
            {
                Debug.WriteLine(ExecList.ElementAt(i).ExecCommand + " - " + ExecList.ElementAt(i).WaitForCommand + " - " + ExecList.ElementAt(i).WaitSecs);
            }

            Debug.WriteLine("------------------------");
        }




        //handles ExecutionStarted-events
        private void DisableContols(String szExecutablename)
        {
            Debug.WriteLine("Hiding contol-elements of mainwindow during execution");

            commandsActive = true;

            this.Dispatcher.Invoke
            (
                System.Windows.Threading.DispatcherPriority.Normal,
               new System.Action
               (
                   delegate()
                   {
                       buttonOK.IsEnabled = false;
                       buttonOK.Content = "Cancelling not possible";

                       label.Content = szExecutablename + " is running";
                       
                       passwordField.Visibility = System.Windows.Visibility.Hidden;
                       buttonConfig.Visibility = System.Windows.Visibility.Hidden;

                       progressBar.Visibility = System.Windows.Visibility.Visible;
                       ProgresbarLabel.Visibility = System.Windows.Visibility.Visible;
                   }
               )
            );
        }

        //handles ExecutionCompleted-events
        private void EnableContols()
        {
            Debug.WriteLine("Unhiding contol-elements of mainwindow after execution");

            commandsActive = false;

            this.Dispatcher.Invoke
            (
                System.Windows.Threading.DispatcherPriority.Normal,
               new System.Action
               (
                   delegate()
                   {
                       ProgresbarLabel.Visibility = System.Windows.Visibility.Hidden;
                       progressBar.Visibility = System.Windows.Visibility.Hidden;

                       buttonConfig.Visibility = System.Windows.Visibility.Visible;
                       passwordField.Visibility = System.Windows.Visibility.Visible;

                       label.Content = "Please type in the password:";

                       buttonOK.IsEnabled = true;
                       buttonOK.Content = "OK";
                   }
               )
            );
        }

        private void PWAskerMainWnd_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (commandsActive)
            {
                Debug.Write("User tried to close window during execution and ");

                if (MessageBox.Show("Closing the Application during execution is not recommended.\r\nDo you want to exit anyway?", "Commands are still executed", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    Debug.WriteLine("forced quit.");
                }
                else
                {
                    e.Cancel = true;
                    Debug.WriteLine("decided to wait.");
                }
            }
        }
    }
}
